package cn.flant.io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Serializable;
import java.io.Writer;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.net.Socket;

import cn.flant.io.tools.BytePiped;
import cn.flant.io.tools.CharPiped;
import cn.flant.io.tools.StreamPumper;

public final class IOUtil {
	private IOUtil() {
	}

	public static BytePiped getBytePiped() throws IOException {
		return BytePiped.open();
	}

	public static CharPiped getCharPiped() throws IOException {
		return CharPiped.open();
	}

	public static StreamPumper streamPumper(InputStream remoteInput, OutputStream localOutput) {
		StreamPumper io = new StreamPumper(remoteInput, localOutput);
		Thread t = new Thread(io);
		t.setDaemon(true);
		t.start();
		return io;
	}

	public static StreamPumper[] readWrite(InputStream remoteInput, OutputStream remoteOutput, InputStream localInput, OutputStream localOutput) {
		StreamPumper[] pumpers = new StreamPumper[2];
		pumpers[0] = streamPumper(localInput, remoteOutput);
		pumpers[1] = streamPumper(remoteInput, localOutput);
		return pumpers;
	}

	public static void saveFile(InputStream in, File file) throws Exception {
		FileOutputStream out = new FileOutputStream(file);
		try {
			byte[] buf = new byte[1024];
			int c = -1;
			while ((c = in.read(buf)) >= 0) {
				out.write(buf, 0, c);
			}
		} finally {
			close(out);
		}
	}

	public static void saveObject(Serializable obj, File file) throws Exception {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ObjectOutputStream oos = null;
		try {
			oos = new ObjectOutputStream(baos);
			oos.writeObject(obj);
			oos.flush();
		} finally {
			close(oos);
		}
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(file);
			fos.write(baos.toByteArray());
			fos.flush();
		} finally {
			close(fos);
		}
	}

	@SuppressWarnings("unchecked")
	public static <T extends Serializable> T loadObject(File file) throws Exception {
		ObjectInputStream input = null;
		try {
			input = new ObjectInputStream(new FileInputStream(file));
			Object obj = input.readObject();
			return (T) obj;
		} finally {
			IOUtil.close(input);
		}
	}

	public static void close(InputStream in) {
		if (in != null) {
			try {
				in.close();
			} catch (IOException e) {
			}
		}
	}

	public static void close(OutputStream out) {
		if (out != null) {
			try {
				out.close();
			} catch (IOException e) {
			}
		}
	}

	public static void close(Reader reader) {
		if (reader != null) {
			try {
				reader.close();
			} catch (IOException e) {
			}
		}
	}

	public static void close(Writer writer) {
		if (writer != null) {
			try {
				writer.close();
			} catch (IOException e) {
			}
		}
	}

	public static void close(BufferedReader reader) {
		if (reader != null) {
			try {
				reader.close();
			} catch (IOException e) {
			}
		}
	}

	public static void close(BufferedWriter writer) {
		if (writer != null) {
			try {
				writer.close();
			} catch (IOException e) {
			}
		}
	}

	public static void close(FileInputStream in) {
		if (in != null) {
			try {
				in.close();
			} catch (IOException e) {
			}
		}
	}

	public static void close(FileOutputStream out) {
		if (out != null) {
			try {
				out.close();
			} catch (IOException e) {
			}
		}
	}

	public static void close(Socket socket) {
		if (socket != null && !socket.isClosed()) {
			try {
				socket.close();
			} catch (IOException e) {
			}
		}
	}

	public static void close(DatagramSocket socket) {
		if (socket != null && !socket.isClosed()) {
			try {
				socket.close();
			} catch (Exception e) {
			}
		}
	}

	public static void close(ServerSocket server) {
		if (server != null && !server.isClosed()) {
			try {
				server.close();
			} catch (IOException e) {
			}
		}
	}

}
